package thread;

import java.util.PriorityQueue;
//通过这个类,来描述一个任务
class MyTimerTask implements Comparable<MyTimerTask>{//实现比较接口
    //在什么时间点来执行这个任务
    //此时约定这个time是一个ms级别的时间戳
    private long time;
    //师级人物要执行的代码
    private Runnable runnable;
    public long getTime() {
        return time;
    }
    //delay 期望是一个"相对"时间
    public MyTimerTask(Runnable runnable,long delay) {
        this.runnable = runnable;
        //计算一下真正要执行任务的绝对时间(使用它方便判定任务是否到达时间

        this.time = System.currentTimeMillis() + delay;
    }
    public void run() {
        runnable.run();
    }

    @Override
    public int compareTo(MyTimerTask o) {
        //时间小的作为优先级越高
       // return  (int)(o.time - this.time);//这个要来试一试,谁减去谁
        return  (int)(this.time - o.time);//这个要来试一试,谁减去谁
    }
}
//通过这个类,来表示一个计时器
class MyTimer {
    //负责扫描任务队列,执行任务的线程
    private Thread t = null;
    //任务队列
    private PriorityQueue<MyTimerTask> queue = new PriorityQueue<MyTimerTask>();//俩个线程操作同一个队列,所有需要加锁来解决线程安全问题
    //搞个锁对象
    Object locker = new Object();
    public void schedule(Runnable runnable,long delay) {
      synchronized (locker) {
          MyTimerTask task = new MyTimerTask(runnable, delay);//创建一个任务
          queue.offer(task);
          //添加新的元素之后,就能唤醒扫描的wait了
          locker.notify();
      }
    }
    public void cancle() {
        //结束t线程即可
        //intrrupt
        t.interrupt();
    }
    //构造方法,扫描线程来完成判定和执行
    //加入日志getId来看有多少个线程
    public MyTimer() {
        t = new Thread(() ->{//再队列进行删除
           //扫描线程就需要循环的扫描队首元素,然后判定队首元素是不是时间到了
           //如果时间没到,啥也不干
           //如果时间到了,就执行这个任务并且把这个任务从队列中删除掉

            while (!Thread.currentThread().isInterrupted()) {//但是可能会出现线程饿死的情况
                try {
                    synchronized (locker) {//这个锁是保护队列用的
                        while (queue.isEmpty()) {//如果为空,继续循环是没有意义的
                            //暂时先不处理
                            locker.wait();
//                        continue;
                        }
                        MyTimerTask task = queue.peek();
                        //获取当前时间
                        long curTime = System.currentTimeMillis();
                        if (curTime >= task.getTime()) {
                            //当前时间已经达到了任务时间,就可以执行任务了
                            queue.poll();
                            task.run();
                        } else {
                            //当前时间还没到,先不执行
                            //也需要wait,不然就会出现忙等
                            //不能sleep,不然会错过新的任务,也无法释放锁
                            locker.wait(task.getTime() - curTime);//有新的任务来了,就会被唤醒,或者时间到了,就会按照原定计划来执行
                            continue;
                        }
                    }
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }

        });
        //记得start
        t.start();
    }

}
public class ThreadDemo31 {
    public static void main(String[] args) {
    MyTimer timer = new MyTimer();//主线程对队列元素进行添加
    timer.schedule(new Runnable() {
        @Override
        public void run() {
            System.out.println("hello 3000");
        }
    },3000);
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 2000");
            }
        },2000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello 1000");
            }
        },1000);
        System.out.println("hello main");
//        timer.cancle();


    }
}

